not logged in | [Login]
Always use radiusd -X
when debugging!
This first example assumes the server is only performing mac-auth. It checks MAC addresses against a users style file.
Most NASes usually send the MAC address in the Calling-Station-ID attribute. There are several common formats:
Again, depending on the NAS, these can be either upper-case or lower-case hex.
It is sensible to re-format these into a single format at the server. The
following policy is available in FreeRADIUS version 3 onwards, in
[[raddb/policy.d/canonicalization|https://github.com/FreeRADIUS/freeradius-server/blob/v3.0.x/raddb/policy.d/canonicalization
.
# # Rewrite called station id attribute into a standard format. # rewrite_calling_station_id { if (Calling-Station-Id =~ /([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:.]?([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:.]?([0-9a-f]{2})[-:]?([0-9a-f]{2})/i) { update request { Calling-Station-Id := "%{tolower:%{1}-%{2}-%{3}-%{4}-%{5}-%{6}}" } } else { noop } }
Create a new instance of the files module to read a new file of permitted MAC addresses.
files authorized_macs { # The default key attribute to use for matches. The content # of this attribute is used to match the "name" of the # entry. key = "%{Calling-Station-ID}" usersfile = ${confdir}/authorized_macs # If you want to use the old Cistron 'users' file # with FreeRADIUS, you should change the next line # to 'compat = cistron'. You can the copy your 'users' # file from Cistron. compat = no }
This is the list of permitted MAC addresses, as read by the new files configuration above.
00-11-22-33-44-55 Reply-Message = "Device with MAC Address %{Calling-Station-Id} authorized for network access"
Finally, call the canonicalisation policy and new files module from the authorize section:
authorize { preprocess # If cleaning up the Calling-Station-Id... rewrite_calling_station_id # Now check against the authorized_macs file authorized_macs if (!ok) { # No match was found, so reject reject } else { # The MAC address was found, so update Auth-Type # to accept this auth. update control { Auth-Type := Accept } } }
This example shows how to mix 802.1x and mac-auth. The example does the following:
The files raddb/policy.conf
, raddb/mods-available/files
and raddb/authorized_macs
are the same as the plain mac-auth examples above.
authorize { preprocess # If cleaning up the Calling-Station-Id... rewrite_calling_station_id # If this is NOT 802.1x, assume mac-auth. We check this by testing # for the presence of the EAP-Message attribute in the request. if (!EAP-Message) { # Now check against the authorized_macs file authorized_macs if (!ok) { reject } else { # accept update control { Auth-Type := Accept } } } else { # Normal FreeRADIUS virtual server config goes here e.g. eap } }
This example shows how to perform both 802.1x and mac-auth. The example does the following:
The files raddb/policy.conf
, raddb/mods-available/files
and raddb/authorized_macs
are the same as the plain mac-auth examples above.
authorize { preprocess # If cleaning up the Calling-Station-Id... rewrite_calling_station_id # always check against the authorized_macs file first authorized_macs if (!ok) { # Reject if the MAC address was not permitted. reject } # If this is NOT 802.1x, mac-auth if (!EAP-Message) { # MAC address has already been checked, so accept update control { Auth-Type := Accept } } else { # Normal FreeRADIUS virtual server config goes here e.g. eap } }
Although this configuration is more complex, you should probably use it if the server is going to process both web-auth and mac-auth requests, here is the rationale:
This configuration attempts to prevent this kind of spoofing:
Service-Type == 'Call-Check'
AVP as an explicit indication that the NAS wants to do Mac-Auth. If your NAS sends this in Access-Request packets, you should remove the User-Name =~ /^%{Calling-Station-ID}$/i
sub-condition from the authorize section.For this configuration to work, you must configure the password format for Mac-Auth to use the same octet separator as the Calling-Station-ID attribute.
As per example 1
As per example 1
As per example 1
authorize { # # (Optional) May help if your NAS doesn't let you specify separators for the User-Name value # #rewrite_calling_station_id # # The EAP module should be listed before the Mac-Auth section if concurrent 802.1X/MAC authentication # (Mac-Auth bypass etc...) is being used. # eap # # Machine (Calling-Station-ID based) authentication # # RFC 2865 says that a Service-Type value of Call Check is used # to specify this kind of authentication (though were now dealing with ethernet ports instead of lines). # if((Service-Type == 'Call-Check') || (User-Name =~ /^%{Calling-Station-ID}$/i)){ update control { Auth-Type = 'CSID' } } # # If the CHAP module is called, it must be *after* the check for CSID authentication # # chap } authenticate { # # Authentication based on Calling-Station-ID # # Calling-Station-ID authentication is usually done by comparing normalised # forms of the Calling-Station-ID and User-name fields. # Auth-Type CSID { # # Optionally a CHAP-Password attribute is included which is # md5(ChapID + Calling-Station-ID + Request Authenticator). # if(Chap-Password){ update control { Cleartext-Password := "%{Calling-Station-ID}" } chap } else { ok } } } post-auth { if(control:Auth-Type == 'CSID'){ # Authorization happens here authorized_macs.authorize if(!ok){ reject } } }
Follow any of the recipes above and then make the following modifications.
Note: The recipe below will work with any NAS that includes the SSID in the Called-Station-ID string with the format : e.g. 00-11-22-33-44-55:MY_SSID_1
. There is no standard for this, and vendors may include the SSID in its own vendor specific attribute (VSA). If unsure, run the server in debug mode (-X) and check the contents of incoming requests.
If your vendor's NAS uses a VSA, omit the call to 'rewrite_called_station_id', do not add the additional attributes to the dictionary, and insert that VSA into the key attribute in place of '%{Called-Station-SSID}' e.g. key = "%{VENDOR_SSID_VSA}.%{Calling-Station-ID}"
.
Use next free attribute number between 3000-4000 and insert the following definition.
# The SSID the supplicant/user device connected to ATTRIBUTE Called-Station-SSID 3010 string
Add the following policy stanza to policy.conf.
# # Rewrite called station id attribute into a standard format. # If a 6th seperator is present, write the trailing chars into Called-Station-SSID # rewrite_called_station_id { if(Called-Station-Id =~ /^([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:.]?([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:.]?([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:]?([-a-z0-9_. ]*)?/i){ update request { Called-Station-Id := "%{1}%{2}%{3}%{4}%{5}%{6}" Called-Station-SSID := "%{7}" } } else { noop } }
Add the a module call for 'rewrite_calling_station_id' to the authorize section directly above the call to 'rewrite_calling_station_id'.
authorize { ... # break called station ID into the BSSID and SSID rewrite_called_station_id # if cleaning up the Calling-Station-Id... rewrite_calling_station_id ... }
modify the key attribute of the authorized_macs files instance
files authorized_macs { # The default key attribute to use for matches. The content # of this attribute is used to match the "name" of the # entry. key = "%{Called-Station-SSID}.%{Calling-Station-ID}" usersfile = ${confdir}/authorized_macs # If you want to use the old Cistron 'users' file # with FreeRADIUS, you should change the next line # to 'compat = cistron'. You can the copy your 'users' # file from Cistron. compat = no }
Entries should now be in the following format.
MY_SSID_1.00-11-22-33-44-55 Reply-Message = "Device with MAC Address %{Calling-Station-Id} authorized for network access on SSID %{Called-Station-SSID}"
As above.
As above.
Add the a module call for 'rewrite_calling_station_id' to the authorize section directly above the call to 'rewrite_calling_station_id'.
authorize { preprocess rewrite_calling_station_id rewrite_called_station_id if("%{sql:SELECT COUNT(*) FROM `SSIDMACAUTH` WHERE macaddress = '%{Calling-Station-ID}' AND SSID = '%{Called-Station-SSID}'}" >= 1){ ok update control { Auth-Type := Accept } } else{ reject } }
Last edited by Matthew Newton (mcnewton), 2016-04-17 21:00:55
Sponsored by Network RADIUS